package com.zhengxing.jienci.user.service.rbac.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.CaseFormat;
import com.google.common.collect.Lists;
import com.zhengxing.jienci.user.domain.rbac.ResourceFunc;
import com.zhengxing.jienci.common.util.IdGenerateUtil;
import com.zhengxing.jienci.user.mapper.rbac.ResourceFuncMapper;
import com.zhengxing.jienci.user.service.rbac.ResourceFuncService;
import com.zhengxing.jienci.user.service.rbac.RoleResourceFuncService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * ResourceFuncServiceImpl
 *
 * @author philbert
 * @version 1.00
 */
@Slf4j
@Service
@Transactional
@Lazy
public class ResourceFuncServiceImpl extends ServiceImpl<ResourceFuncMapper, ResourceFunc> implements ResourceFuncService {

    @Autowired
    private ResourceFuncMapper resourceFuncMapper;
    @Autowired
    private RoleResourceFuncService roleResourceFuncService;

    /**
     * 保存资源功能
     *
     * @param resourceFunc 资源功能
     * @return true=成功；false=失败
     */
    @Override
    public boolean save(ResourceFunc resourceFunc) {
        if (StringUtils.isBlank(resourceFunc.getId())) resourceFunc.setId(IdGenerateUtil.getId());
        if (resourceFunc.getCreatedAt() == null) resourceFunc.setCreatedAt(System.currentTimeMillis());
        return super.retBool(resourceFuncMapper.insert(resourceFunc));
    }

    /**
     * 删除资源功能
     *
     * @param id 主键
     * @return true=成功；false=失败
     */
    @Override
    public boolean delete(String id) {
        roleResourceFuncService.deleteByResourceFuncIds(Lists.newArrayList(id));
        resourceFuncMapper.deleteById(id);
        return true;
    }

    /**
     * 更新资源功能
     *
     * @param resourceFunc 资源功能
     * @return true=成功；false=失败
     */
    @Override
    public boolean update(ResourceFunc resourceFunc) {
        if (resourceFunc.getCreatedAt() == null) resourceFunc.setUpdatedAt(System.currentTimeMillis());
        return super.retBool(resourceFuncMapper.updateById(resourceFunc));
    }

    /**
     * 查询资源功能
     *
     * @param id 主键
     * @return 资源功能
     */
    @Override
    @Transactional(readOnly = true)
    public ResourceFunc get(String id) {
        return resourceFuncMapper.selectById(id);
    }

    /**
     * 查询资源功能分页对象
     *
     * @param paramMap 参数Map
     * @param orderBy  排序方式
     * @param pageNo   页码
     * @param pageSize 每页最大数量
     * @return 资源功能分页对象
     */
    @Override
    @Transactional(readOnly = true)
    public IPage<ResourceFunc> getPagination(Map<String, Object> paramMap, String orderBy, int pageNo, int pageSize) {
        String resourceId = MapUtils.getString(paramMap, "resourceId");
        String name = MapUtils.getString(paramMap, "name");
        String code = MapUtils.getString(paramMap, "code");

        QueryWrapper<ResourceFunc> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(orderBy)) {
            String[] array = orderBy.split(" ");
            String format = "CONVERT(%s USING gbk)";
            String field = String.format(format, CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, array[0]));
            if (StringUtils.equalsIgnoreCase(array[1], "asc")) {
                queryWrapper.orderByAsc(field);
            } else if (StringUtils.equalsIgnoreCase(array[1], "desc")) {
                queryWrapper.orderByDesc(field);
            } else {
                throw new RuntimeException();
            }
        }
        LambdaQueryWrapper<ResourceFunc> lambdaQueryWrapper = queryWrapper.lambda();
        lambdaQueryWrapper.eq(ResourceFunc::getResourceId, resourceId);
        lambdaQueryWrapper.ne(ResourceFunc::getCode, "list");
        if (StringUtils.isNotBlank(name)) lambdaQueryWrapper.and(obj -> obj.like(ResourceFunc::getName, name));
        if (StringUtils.isNotBlank(code)) lambdaQueryWrapper.and(obj -> obj.like(ResourceFunc::getCode, code));

        Page<ResourceFunc> page = new Page<>(pageNo, pageSize);

        return resourceFuncMapper.selectPage(page, queryWrapper);
    }

    /**
     * 查询名称是否已存在
     *
     * @param resourceId 资源主键
     * @param name       名称
     * @param excludId   要排除的记录主键
     * @return true=已存在；false=不存在
     */
    @Override
    @Transactional(readOnly = true)
    public boolean nameExist(String resourceId, String name, String excludId) {
        SFunction<ResourceFunc, String> sFunction = ResourceFunc::getName;
        LambdaQueryWrapper<ResourceFunc> lambdaQueryWrapper = this.genLambdaQueryWrapper(sFunction, name, resourceId, excludId);
        return !resourceFuncMapper.selectList(lambdaQueryWrapper).isEmpty();
    }

    /**
     * 查询代码是否已存在
     *
     * @param resourceId 资源主键
     * @param code       代码
     * @param excludId   要排除的记录主键
     * @return true=已存在；false=不存在
     */
    @Override
    @Transactional(readOnly = true)
    public boolean codeExist(String resourceId, String code, String excludId) {
        SFunction<ResourceFunc, String> sFunction = ResourceFunc::getCode;
        LambdaQueryWrapper<ResourceFunc> lambdaQueryWrapper = this.genLambdaQueryWrapper(sFunction, code, resourceId, excludId);
        return !resourceFuncMapper.selectList(lambdaQueryWrapper).isEmpty();
    }

    /**
     * 根据资源主键集合删除资源功能
     *
     * @param resourceIds     资源主键集合
     * @param includeListFunc 是否删除列表功能
     */
    @Override
    public void deleteByResourceIds(Collection<String> resourceIds, boolean includeListFunc) {
        LambdaUpdateWrapper<ResourceFunc> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        if (!includeListFunc) lambdaUpdateWrapper.ne(ResourceFunc::getCode, "list");
        if (!resourceIds.isEmpty()) {
            if (resourceIds.size() == 1)
                resourceIds.forEach(resourceId -> lambdaUpdateWrapper.eq(ResourceFunc::getResourceId, resourceId));
            else
                lambdaUpdateWrapper.in(ResourceFunc::getResourceId, resourceIds);

            resourceFuncMapper.delete(lambdaUpdateWrapper);
        }
    }

    /**
     * 通过资源主键查询资源功能
     *
     * @param resourceId 资源主键
     * @return 该资源的功能
     */
    @Transactional(readOnly = true)
    public List<ResourceFunc> findByResourceId(String resourceId) {
        LambdaQueryWrapper<ResourceFunc> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ResourceFunc::getResourceId, resourceId);
        lambdaQueryWrapper.ne(ResourceFunc::getCode, "list");
        lambdaQueryWrapper.orderByAsc(ResourceFunc::getSortNo);
        return resourceFuncMapper.selectList(lambdaQueryWrapper);
    }

    /**
     * 通过资源主键查询资源列表功能的主键
     *
     * @param resourceId 资源主键
     * @return 资源列表功能的主键
     */
    @Transactional(readOnly = true)
    public String getListFuncIdByResourceId(String resourceId) {
        LambdaQueryWrapper<ResourceFunc> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ResourceFunc::getResourceId, resourceId);
        lambdaQueryWrapper.eq(ResourceFunc::getCode, "list");
        ResourceFunc resourceFunc = resourceFuncMapper.selectOne(lambdaQueryWrapper);
        return resourceFunc.getId();
    }

    private LambdaQueryWrapper<ResourceFunc> genLambdaQueryWrapper(SFunction<ResourceFunc, String> sFunction,
                                                                   String value, String resourceId, String excludId) {
        LambdaQueryWrapper<ResourceFunc> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.select(ResourceFunc::getId);
        lambdaQueryWrapper.eq(ResourceFunc::getResourceId, resourceId);
        lambdaQueryWrapper.eq(sFunction, value);
        if (StringUtils.isNotBlank(excludId)) lambdaQueryWrapper.ne(ResourceFunc::getId, excludId);
        return lambdaQueryWrapper;
    }

}
